package com.openspring.framework.controller;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.openspring.framework.annotation.persistence.Column;
import com.openspring.framework.annotation.persistence.Table;

import org.codehaus.jackson.type.TypeReference;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import com.openspring.framework.common.Filter;
import com.openspring.framework.common.Paging;
import com.openspring.framework.common.Sorter;
import com.openspring.framework.service.GenericService;
import com.openspring.framework.util.ResultUtils;
import com.openspring.framework.util.GenericUtils;
import com.openspring.framework.util.JacksonUtils;
import com.openspring.framework.util.StringUtils;

public class GenericController<T, ID extends Serializable> {
	
	private GenericService<T, ID> genericService;

	protected void setGenericService(GenericService<T, ID> genericService) {
		this.genericService = genericService;
	}
	
	@InitBinder
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }
	
	@SuppressWarnings("unchecked")
	public Map<String, Object> doQuery(Paging paging, String filter, String sort) {
		StringBuffer sbf = new StringBuffer();
		Map<String, Object> filters = parseFilter(filter);
		List<Object> values = new ArrayList<Object>();
		if(!filters.isEmpty()) {
			sbf.append(" WHERE ").append(filters.get("sql").toString());
			values = (List<Object>)filters.get("values");
		}
		int totalCount = genericService.getTotalCount(sbf.toString(), values.toArray());
		sbf.append(parseSorter(sort));
		List<T> entities = null;
		if(totalCount > 0) {
			if(paging != null && paging.getLimit() > 0) {
				sbf.append(" LIMIT ? OFFSET ?");
				values.add(paging.getLimit());
				values.add(paging.getStart());
			}
			entities = genericService.findWhere(sbf.toString(), values.toArray());
		}
		return ResultUtils.datas(totalCount, entities);
	}
	
	public Map<String, Object> doQuery(String whereSql, Object... values) {
		int totalCount = genericService.getTotalCount(whereSql, values);
		List<T> entities = null;
		if(totalCount > 0) {
			entities = genericService.find(whereSql, values);
		}
		return ResultUtils.datas(totalCount, entities);
	}
	
	/**
	 * sort为空则返回空字符串
	 * @param sort JSON格式的字符串
	 * @return " ORDER BY Property ASC/DESC, ..."
	 */
	protected String parseSorter(String sort, Class<?> cls) {
		if(StringUtils.isTrimEmpty(sort)) {
			return "";
		}
		StringBuffer sbf = new StringBuffer(" ORDER BY ");
		List<Sorter> result = JacksonUtils.readValue(sort, new TypeReference<List<Sorter>>() {});
		if(result == null || result.isEmpty()) {
			return "";
		}
		Iterator<Sorter> iter = result.iterator();
		while(iter.hasNext()) {
			String alias = "t0";
			Sorter s = iter.next();
			try {
				Table table = cls.getAnnotation(Table.class);
				if(table != null && !StringUtils.isEmpty(table.alias())) {
					alias = StringUtils.addQuotesHasUpperCase(table.alias());
				}
				Method m = cls.getMethod("get" + StringUtils.toInitialUpperCase(s.getProperty()));
				if(m != null) {
					Column c = m.getAnnotation(Column.class);
					if(c != null) {
						if(!StringUtils.isEmpty(c.name()))
							s.setProperty(c.name());
						if(!StringUtils.isEmpty(c.table()))
							alias =  StringUtils.addQuotesHasUpperCase(c.table());
					}
				}
			} catch (SecurityException e) {
				throw new RuntimeException(e);
			} catch (NoSuchMethodException e) {
				throw new RuntimeException(e);
			}
			sbf.append(alias).append('.').append(StringUtils.addQuotesHasUpperCase(s.getProperty())).append(' ').append(s.getDirection());
			if(iter.hasNext()) {
				sbf.append(", ");
			}
		}
		return sbf.toString();
	}
	
	/**
	 * sort为空则返回空字符串
	 * @param sort JSON格式的字符串
	 * @return " ORDER BY Property ASC/DESC, ..."
	 */
	protected String parseSorter(String sort) {
		Class<?> cls = GenericUtils.getGenericSuperArgumentsclass(getClass());
		return parseSorter(sort, cls);
	}
	
	/**
	 * filter为空返回一个空的Map
	 * @param filter
	 * @return map.put("sql", String); map.put("values", List);
	 */
	protected Map<String, Object> parseFilter(String filter, Class<?> cls) {
		Map<String, Object> map = new HashMap<String, Object>();
		if(StringUtils.isTrimEmpty(filter)) {
			return map;
		}
		StringBuffer sbf = new StringBuffer();
		List<Object> list = new ArrayList<Object>();
		List<Filter> result = JacksonUtils.readValue(filter, new TypeReference<List<Filter>>() {});
		if(result == null || result.isEmpty()) {
			return map;
		}
		Iterator<Filter> iter = result.iterator();
		while(iter.hasNext()) {
			String alias = "t0";
			Filter f = iter.next();
			/**
			 * 这里后期需要做防SQL注入
			 */
			try {
				Table table = cls.getAnnotation(Table.class);
				if(table != null && !StringUtils.isEmpty(table.alias())) {
					alias = StringUtils.addQuotesHasUpperCase(table.alias());
				}
				Method m = cls.getMethod("get" + StringUtils.toInitialUpperCase(f.getProperty()));
				if(m != null) {
					Column c = m.getAnnotation(Column.class);
					if(c != null) {
						if(!StringUtils.isEmpty(c.name()))
							f.setProperty(c.name());
						if(!StringUtils.isEmpty(c.table()))
							alias =  StringUtils.addQuotesHasUpperCase(c.table());
					}
				}
			} catch (SecurityException e) {
				throw new RuntimeException(e.getMessage());
			} catch (NoSuchMethodException e) {
				throw new RuntimeException(e.getMessage());
			}
			sbf.append(f.getJoin().toUpperCase()).append(' ').append(alias).append('.').append(StringUtils.addQuotesHasUpperCase(f.getProperty())).append(' ').append(f.getCondition()).append(" ? ");
			list.add(f.getValue());
		}
		map.put("sql", sbf.toString().trim());
		map.put("values", list);
		return map;
	}
	
	/**
	 * filter为空返回一个空的Map
	 * @param filter
	 * @return map.put("sql", String); map.put("values", List);
	 */
	protected Map<String, Object> parseFilter(String filter) {
		Class<?> cls = GenericUtils.getGenericSuperArgumentsclass(getClass());
		return parseFilter(filter, cls);
	}
}
